/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus's Graphical User Interface
// Copyright (C) 2012 Bruno Van de Velde (VDV_B@hotmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#ifndef _TGUI_GROUP_INCLUDED_
#define _TGUI_GROUP_INCLUDED_

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace tgui
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    struct TGUI_API Group
    {
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Default constructor
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Group();


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Copy constructor
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Group(const Group& copy);


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Destructor
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual ~Group();


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Overload of assignment operator
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Group& operator= (const Group& right);


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a label to the group. You can optionally pass an object name.
        /// If you want to access the label later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Label*       addLabel(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a picture to the group. You can optionally pass an object name.
        /// If you want to access the picture later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Picture*     addPicture(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a button to the group. You can optionally pass an object name.
        /// If you want to access the button later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Button*      addButton(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a checkbox to the group. You can optionally pass an object name.
        /// If you want to access the checkbox later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Checkbox*    addCheckbox(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a radio button to the group. You can optionally pass an object name.
        /// If you want to access the radio button later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        RadioButton* addRadioButton(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add an edit box to the group. You can optionally pass an object name.
        /// If you want to access the edit box later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        EditBox*     addEditBox(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a slider to the group. You can optionally pass an object name.
        /// If you want to access the slider later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Slider*      addSlider(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a scrollbar to the group. You can optionally pass an object name.
        /// If you want to access the scrollbar later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Scrollbar*   addScrollbar(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a listbox to the group. You can optionally pass an object name.
        /// If you want to access the listbox later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Listbox*     addListbox(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a loading bar to the group. You can optionally pass an object name.
        /// If you want to access the loading bar later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        LoadingBar*  addLoadingBar(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a panel to the group. You can optionally pass an object name.
        /// If you want to access the panel later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Panel*       addPanel(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a combo box to the group. You can optionally pass an object name.
        /// If you want to access the combo box later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ComboBox*    addComboBox(const std::string objectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a text box to the group. You can optionally pass an object name.
        /// If you want to access the text box later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        TextBox*     addTextBox(const std::string objectName = "");


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Create and add a sprtie sheet to the group. You can optionally pass an object name.
        /// If you want to access the sprite sheet later then you must do this with the object name.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        SpriteSheet* addSpriteSheet(const std::string objectName = "");


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the label.
        /// The object name is the same as when you created the objects (with the addLabel function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Label*       getLabel(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the picture.
        /// The object name is the same as when you created the objects (with the addPicture function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Picture*     getPicture(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the button.
        /// The object name is the same as when you created the objects (with the addButton function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Button*      getButton(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the checkbox.
        /// The object name is the same as when you created the objects (with the addCheckbox function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Checkbox*    getCheckbox(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the radio button.
        /// The object name is the same as when you created the objects (with the addRadioButton function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        RadioButton* getRadioButton(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the edit box.
        /// The object name is the same as when you created the objects (with the addEditBox function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        EditBox*     getEditBox(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the slider.
        /// The object name is the same as when you created the objects (with the addSlider function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Slider*      getSlider(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the scrollbar.
        /// The object name is the same as when you created the objects (with the addScrollbar function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Scrollbar*   getScrollbar(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the listbox.
        /// The object name is the same as when you created the objects (with the addListbox function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Listbox*     getListbox(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the loading bar.
        /// The object name is the same as when you created the objects (with the addLoadingBar function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        LoadingBar*  getLoadingBar(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the panel.
        /// The object name is the same as when you created the objects (with the addPanel function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Panel*       getPanel(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the combo box.
        /// The object name is the same as when you created the objects (with the addComboBox function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ComboBox*    getComboBox(const std::string objectName);

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the text box.
        /// The object name is the same as when you created the objects (with the addTextBox function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        TextBox*     getTextBox(const std::string objectName);


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// This function is used to get back the pointer to the sprite sheet.
        /// The object name is the same as when you created the objects (with the addSpriteSheet function).
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        SpriteSheet* getSpriteSheet(const std::string objectName);


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of any existing object and returns the pointer to the new object.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        template <typename T>
        T* copyObject(T* oldObject, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing label and returns the pointer to the new label.
        /// The difference with the copyObject function is that you pass the name of the old label
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Label*       copyLabel(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing picture and returns the pointer to the new picture.
        /// The difference with the copyObject function is that you pass the name of the old picture
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Picture*     copyPicture(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing button and returns the pointer to the new button.
        /// The difference with the copyObject function is that you pass the name of the old button
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Button*      copyButton(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing checkbox and returns the pointer to the new checkbox.
        /// The difference with the copyObject function is that you pass the name of the old checkbox
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Checkbox*    copyCheckbox(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing radio button and returns the pointer to the new radio button.
        /// The difference with the copyObject function is that you pass the name of the old radio button
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        RadioButton* copyRadioButton(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing edit box and returns the pointer to the new edit box.
        /// The difference with the copyObject function is that you pass the name of the old edit box
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        EditBox*     copyEditBox(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing slider and returns the pointer to the new slider.
        /// The difference with the copyObject function is that you pass the name of the old slider
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Slider*      copySlider(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing scrollbar and returns the pointer to the new scrollbar.
        /// The difference with the copyObject function is that you pass the name of the old scrollbar
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Scrollbar*   copyScrollbar(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing listbox and returns the pointer to the new listbox.
        /// The difference with the copyObject function is that you pass the name of the old listbox
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Listbox*     copyListbox(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing loading bar and returns the pointer to the new loading bar.
        /// The difference with the copyObject function is that you pass the name of the old loading bar
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        LoadingBar*  copyLoadingBar(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing panel and returns the pointer to the new panel.
        /// The difference with the copyObject function is that you pass the name of the old panel
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Panel*       copyPanel(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing combo box and returns the pointer to the new combo box.
        /// The difference with the copyObject function is that you pass the name of the old combo box
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ComboBox*    copyComboBox(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing text box and returns the pointer to the new text box.
        /// The difference with the copyObject function is that you pass the name of the old text box
        /// instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        TextBox*     copyTextBox(const std::string oldObjectName, const std::string newObjectName = "");

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Makes a copy of an existing sprite sheet and returns the pointer to the new sprite sheet.
        /// The difference with the copyObject function is that you pass the name of the old
        /// sprite sheet instead of passing a pointer to it.
        /// When a wrong object name was passed then this function will return NULL.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        SpriteSheet* copySpriteSheet(const std::string oldObjectName, const std::string newObjectName = "");


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Returns a list of all the objects.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        std::vector<OBJECT*>& getObjects();


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Returns a list of the names of all the objects.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        std::vector<std::string>& getObjectNames();


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Removes a single object that was added to the panel.
        /// If there are multiple objects with the same name then only the first matching object
        /// will be removed.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void removeObject(const std::string objectName);


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Removes all objects that were added to the panel.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void removeAllObjects();


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Focuses an object.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void focus(OBJECT* object);


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Unfocuses an object.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void unfocus(OBJECT* object);


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Uncheck all the radio buttons.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void uncheckRadioButtons();


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Add a callback to the list in tgui::Window, which can be obtained by calling the getCallback
        /// function of the window.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        virtual void addCallback(Callback& callback) = 0;


        //////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Update the internal clock to make animation possible.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void updateTime(const sf::Time& elapsedTime);


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Places an object before all other objects.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void moveObjectToFront(OBJECT* object);


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// Places an object behind all other objects.
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void moveObjectToBack(OBJECT* object);


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    protected:

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        // This function will call the draw function from all the objects in the correct order.
        //////////////////////////////////////////////////////////////////////////////////////////////////////
        void drawObjectGroup(sf::RenderTarget* target, const sf::RenderStates& states) const;


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public:

        /// The internal font, used by all objects by default. If not changed then this is the default SFML font.
        sf::Font globalFont;


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    private:

        std::vector<OBJECT*>      m_Objects;
        std::vector<std::string>  m_ObjName;


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    protected:

        // The internal event manager
        EventManager m_EventManager;

        // Is the group focused? If so, then one of the objects inside the group may be focused
        bool m_GroupFocused;


        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    };

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //_TGUI_GROUP_INCLUDED_
